<?php

/**
 * This file contains the DatabaseConnection class.
 * This class implements the Singleton design pattern to prevent
 * making new connections to the database every time a query is made.
 */

include(__DIR__ . "/../utils/Config.php");

class DatabaseConnection {
    
    private static $instance  = null; // Implementing Singleton design pattern.
    private $databaseLink;
    
    public static function getInstance() { // Implementing Singleton design pattern.
        
        if (is_null(self::$instance)) {
            self::$instance = new self;
        }
        return self::$instance;
        
        // "PHP: self vs. $this", http://stackoverflow.com/questions/151969/php-self-vs-this
        // Essentially, "self" is this class at point of definition, whereas
        // "$this" refers to the _object instance_ of this class, at point of _execution_.
    }
    
    /**
     * Constructor.
     * Visibility is set to private to implement the Singleton design pattern.
     * 
     * @global string $databaseHost
     * @global string $databaseUserName
     * @global string $databasePassword
     * @global string $databaseName
     */
    private function __construct() {
        
        global $databaseHost;
        global $databaseUserName;
        global $databasePassword;
        global $databaseName;
        
        $this->databaseLink = new mysqli(
                $databaseHost,
                $databaseUserName,
                $databasePassword,
                $databaseName);
        
        if ($this->databaseLink->connect_errno) {
            echo "Failed to connect to MySQL: Error "
            . $this->databaseLink->connect_errno
                    . ". " . $this->databaseLink->connect_error;
        }
    }
    
    /**
     * Method: sanitize
     * 
     * Returns the specified string after it has been cleaned, as a first
     * line of defence against MySQL injection attacks.
     * 
     * @param string $inputString
     * The string to be sanitized.
     * 
     * @return string
     */
    public function sanitize($inputString) {
        return $this->databaseLink->real_escape_string($inputString);
    }
    
    /**
     * Method: execute
     * 
     * This method simply runs the MySQL query specified by the $query parameter.
     * 
     * @param string $query
     * @return bool Returns true on success, false otherwise.
     */
    public function execute($query) {
        return $this->databaseLink->real_query($query);
    }
    
    /**
     * Method: getQueryResultAsArray
     * 
     * Returns the result of the specified SQL query as a numeric keyed array
     * of associative keyed arrays (ie. 2-dimensional array). If the query
     * fails, an empty array containing no elements is returned.
     * 
     * @param string $query
     * The MySQL statement to execute.
     * 
     * @return array
     */
    public function getQueryResultAsArray($query) {
        $resultSet = $this->databaseLink->query($query); // returns false on failure.
        
        // Prepare the array to return.
        $numericKeyedArray = array();
        
        if ($resultSet) {
            while ($databaseRow = $resultSet->fetch_array(MYSQLI_ASSOC)) {
                $numericKeyedArray[] = $databaseRow;
            }
        }
        
        $resultSet->free(); // free result set.
        
        return $numericKeyedArray;
    }
    
    /**
     * Method: getIdAfterInsert
     * 
     * Returns the ID generated by the last INSERT (or UPDATE, contrary
     * to the method name) query on a database table that contains a column
     * with the AUTO_INCREMENT attribute.
     * 
     * @param string $insertQuery
     * Contary to the method name, this parameter can be either an INSERT or UPDATE
     * SQL statement.
     * 
     * @return int The value of the AUTO_INCREMENT field that was updated
     * by the last query.   Returns zero if
     * (a) the previous query was not an INSERT or UPDATE statement, or
     * (b) the modified table does not have a column with the AUTO_INCREMENT
     * attribute.
     * 
     */
    public function getIdAfterInsert($insertQuery) {
        $this->databaseLink->query($insertQuery);
        return $this->databaseLink->insert_id;
    }   
    
    /**
     * Method: getErrorMessage
     * 
     * @return string A description of the last error. Returns an empty string
     * if no error has occurred.
     */
    public function getErrorMessage() {
        return $this->databaseLink->error;
    }
}
?>
